from typing import Any, Dict, List, Optional

from sqlalchemy import and_, delete, func, or_, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload, selectinload

from app.core.security import get_password_hash, verify_password
from app.models.menu import Menu
from app.models.user import Dept, Post, Role, User, sys_user_post, sys_user_role
from app.schemas.user import (
    ChangePasswordRequest,
    UpdateProfileRequest,
    UserForm,
    UserQuery,
)
from app.services.base import BaseService


class UserService(BaseService[User]):
    """用户服务 - 匹配RuoYi结构"""

    def __init__(self):
        super().__init__(User)

    async def get_by_username(
        self, db: AsyncSession, *, username: str, tenant_id: Optional[str] = None
    ) -> Optional[User]:
        """根据用户名获取用户 - RuoYi字段"""
        query = select(User).where(User.user_name == username, User.del_flag == "0")

        if tenant_id:
            query = query.where(User.tenant_id == tenant_id)

        result = await db.execute(query)
        return result.scalar_one_or_none()

    async def get_by_email(
        self, db: AsyncSession, *, email: str, tenant_id: Optional[str] = None
    ) -> Optional[User]:
        """根据邮箱获取用户 - RuoYi字段"""
        query = select(User).where(User.email == email, User.del_flag == "0")

        if tenant_id:
            query = query.where(User.tenant_id == tenant_id)

        result = await db.execute(query)
        return result.scalar_one_or_none()

    async def get_user_list(
        self, db: AsyncSession, *, query: UserQuery, tenant_id: str
    ) -> Dict[str, Any]:
        """获取用户列表 - Plus-UI兼容接口"""
        # 构建查询条件
        stmt = select(User).where(User.tenant_id == tenant_id, User.del_flag == "0")

        # 添加查询条件
        if query.userName:
            stmt = stmt.where(User.user_name.like(f"%{query.userName}%"))
        if query.nickName:
            stmt = stmt.where(User.nick_name.like(f"%{query.nickName}%"))
        if query.phonenumber:
            stmt = stmt.where(User.phonenumber.like(f"%{query.phonenumber}%"))
        if query.status:
            stmt = stmt.where(User.status == query.status)
        if query.deptId:
            stmt = stmt.where(User.dept_id == query.deptId)

        # 关联部门表获取部门名称
        stmt = stmt.options(selectinload(User.dept))

        # 分页
        if hasattr(query, "pageNum") and hasattr(query, "pageSize"):
            offset = (query.pageNum - 1) * query.pageSize if query.pageNum > 0 else 0
            stmt = stmt.offset(offset).limit(query.pageSize)

        # 执行查询
        result = await db.execute(stmt)
        users = result.scalars().all()

        # 获取总数
        count_stmt = select(func.count(User.user_id)).where(
            User.tenant_id == tenant_id, User.del_flag == "0"
        )
        if query.userName:
            count_stmt = count_stmt.where(User.user_name.like(f"%{query.userName}%"))
        if query.nickName:
            count_stmt = count_stmt.where(User.nick_name.like(f"%{query.nickName}%"))
        if query.phonenumber:
            count_stmt = count_stmt.where(
                User.phonenumber.like(f"%{query.phonenumber}%")
            )
        if query.status:
            count_stmt = count_stmt.where(User.status == query.status)
        if query.deptId:
            count_stmt = count_stmt.where(User.dept_id == query.deptId)

        count_result = await db.execute(count_stmt)
        total = count_result.scalar()

        # 构建返回数据
        user_list = []
        for user in users:
            user_dict = {
                "userId": user.user_id,
                "deptId": user.dept_id,
                "userName": user.user_name,
                "nickName": user.nick_name,
                "userType": user.user_type,
                "email": user.email,
                "phonenumber": user.phonenumber,
                "sex": user.sex,
                "avatar": user.avatar,
                "status": user.status,
                "delFlag": user.del_flag,
                "loginIp": user.login_ip,
                "loginDate": user.login_date.isoformat() if user.login_date else None,
                "createTime": user.create_time.isoformat()
                if user.create_time
                else None,
                "updateTime": user.update_time.isoformat()
                if user.update_time
                else None,
                "remark": getattr(user, "remark", None),
                "deptName": user.dept.dept_name if user.dept else None,
                "admin": False,
            }
            user_list.append(user_dict)

        return {"rows": user_list, "total": total}

    async def get_user_info(
        self, db: AsyncSession, *, user_id: int, tenant_id: str
    ) -> Optional[Dict[str, Any]]:
        """获取用户详情 - Plus-UI兼容接口"""
        # 查询用户基本信息
        user_stmt = (
            select(User)
            .options(
                selectinload(User.dept),
                selectinload(User.roles),
                selectinload(User.posts),
            )
            .where(
                User.user_id == user_id,
                User.tenant_id == tenant_id,
                User.del_flag == "0",
            )
        )

        result = await db.execute(user_stmt)
        user = result.scalar_one_or_none()

        if not user:
            return None

        # 获取用户角色
        roles = []
        role_ids = []
        for role in user.roles:
            if role.del_flag == "0":
                roles.append(
                    {
                        "roleId": role.role_id,
                        "roleName": role.role_name,
                        "roleKey": role.role_key,
                        "roleSort": role.role_sort,
                        "status": role.status,
                    }
                )
                role_ids.append(role.role_id)

        # 获取用户岗位
        posts = []
        post_ids = []
        for post in user.posts:
            if post.del_flag == "0":
                posts.append(
                    {
                        "postId": post.post_id,
                        "postName": post.post_name,
                        "postCode": post.post_code,
                        "postSort": post.post_sort,
                        "status": post.status,
                    }
                )
                post_ids.append(post.post_id)

        # 构建返回数据
        user_info = {
            "user": {
                "userId": user.user_id,
                "deptId": user.dept_id,
                "userName": user.user_name,
                "nickName": user.nick_name,
                "userType": user.user_type,
                "email": user.email,
                "phonenumber": user.phonenumber,
                "sex": user.sex,
                "avatar": user.avatar,
                "status": user.status,
                "delFlag": user.del_flag,
                "loginIp": user.login_ip,
                "loginDate": user.login_date.isoformat() if user.login_date else None,
                "createTime": user.create_time.isoformat()
                if user.create_time
                else None,
                "updateTime": user.update_time.isoformat()
                if user.update_time
                else None,
                "remark": getattr(user, "remark", None),
                "dept": {
                    "deptId": user.dept.dept_id,
                    "deptName": user.dept.dept_name,
                    "orderNum": user.dept.order_num,
                }
                if user.dept
                else None,
                "admin": False,
            },
            "roles": roles,
            "roleIds": role_ids,
            "posts": posts,
            "postIds": post_ids,
            "roleGroup": ",".join([role["roleName"] for role in roles]),
            "postGroup": ",".join([post["postName"] for post in posts]),
        }

        return user_info

    async def create_user(
        self, db: AsyncSession, *, user_data: UserForm, tenant_id: str, creator_id: int
    ) -> User:
        """创建用户 - Plus-UI兼容接口"""
        # 创建用户数据
        user_dict = {
            "tenant_id": tenant_id,
            "dept_id": user_data.deptId,
            "user_name": user_data.userName,
            "nick_name": user_data.nickName,
            "user_type": getattr(user_data, "userType", "sys_user"),
            "email": getattr(user_data, "email", ""),
            "phonenumber": getattr(user_data, "phonenumber", ""),
            "sex": getattr(user_data, "sex", "0"),
            "avatar": getattr(user_data, "avatar", None),
            "password": get_password_hash(user_data.password),
            "status": user_data.status,
            "create_by": str(creator_id),
            "update_by": str(creator_id),
        }

        # 创建用户
        user = User(**user_dict)
        db.add(user)
        await db.commit()
        await db.refresh(user)

        # 分配角色
        if hasattr(user_data, "roleIds") and user_data.roleIds:
            role_ids = [int(rid) for rid in user_data.roleIds if rid]
            await self._assign_user_roles(db, user.user_id, role_ids)

        # 分配岗位
        if hasattr(user_data, "postIds") and user_data.postIds:
            post_ids = [int(pid) for pid in user_data.postIds if pid]
            await self._assign_user_posts(db, user.user_id, post_ids)

        return user

    async def update_user(
        self,
        db: AsyncSession,
        *,
        user_id: int,
        user_data: UserForm,
        tenant_id: str,
        updater_id: int,
    ) -> Optional[User]:
        """更新用户 - Plus-UI兼容接口"""
        # 获取用户
        user = await db.get(User, user_id)
        if not user or user.tenant_id != tenant_id or user.del_flag != "0":
            return None

        # 更新用户基本信息
        update_data = {
            "dept_id": user_data.deptId,
            "nick_name": user_data.nickName,
            "email": getattr(user_data, "email", ""),
            "phonenumber": getattr(user_data, "phonenumber", ""),
            "sex": getattr(user_data, "sex", "0"),
            "status": user_data.status,
            "update_by": str(updater_id),
        }

        for key, value in update_data.items():
            setattr(user, key, value)

        # 更新角色
        if hasattr(user_data, "roleIds"):
            role_ids = (
                [int(rid) for rid in user_data.roleIds if rid]
                if user_data.roleIds
                else []
            )
            await self._assign_user_roles(db, user_id, role_ids)

        # 更新岗位
        if hasattr(user_data, "postIds"):
            post_ids = (
                [int(pid) for pid in user_data.postIds if pid]
                if user_data.postIds
                else []
            )
            await self._assign_user_posts(db, user_id, post_ids)

        await db.commit()
        await db.refresh(user)
        return user

    async def delete_user(
        self, db: AsyncSession, *, user_id: int, tenant_id: str
    ) -> bool:
        """删除用户（软删除） - Plus-UI兼容接口"""
        user = await db.get(User, user_id)
        if not user or user.tenant_id != tenant_id:
            return False

        user.del_flag = "1"
        await db.commit()
        return True

    async def reset_password(
        self, db: AsyncSession, *, user_id: int, password: str, tenant_id: str
    ) -> bool:
        """重置密码 - Plus-UI兼容接口"""
        user = await db.get(User, user_id)
        if not user or user.tenant_id != tenant_id or user.del_flag != "0":
            return False

        user.password = get_password_hash(password)
        await db.commit()
        return True

    async def change_status(
        self, db: AsyncSession, *, user_id: int, status: str, tenant_id: str
    ) -> bool:
        """修改用户状态 - Plus-UI兼容接口"""
        user = await db.get(User, user_id)
        if not user or user.tenant_id != tenant_id or user.del_flag != "0":
            return False

        user.status = status
        await db.commit()
        return True

    async def update_profile(
        self, db: AsyncSession, *, user_id: int, profile_data: UpdateProfileRequest
    ) -> bool:
        """更新个人信息 - Plus-UI兼容接口"""
        user = await db.get(User, user_id)
        if not user or user.del_flag != "0":
            return False

        if profile_data.nickName is not None:
            user.nick_name = profile_data.nickName
        if profile_data.email is not None:
            user.email = profile_data.email
        if profile_data.phonenumber is not None:
            user.phonenumber = profile_data.phonenumber
        if profile_data.sex is not None:
            user.sex = profile_data.sex
        if profile_data.avatar is not None:
            user.avatar = profile_data.avatar

        await db.commit()
        return True

    async def change_password(
        self, db: AsyncSession, *, user_id: int, old_password: str, new_password: str
    ) -> bool:
        """修改密码 - Plus-UI兼容接口"""
        user = await db.get(User, user_id)
        if not user or user.del_flag != "0":
            return False

        # 验证原密码
        if not verify_password(old_password, user.password):
            return False

        # 更新密码
        user.password = get_password_hash(new_password)
        await db.commit()
        return True

    async def get_auth_role(
        self, db: AsyncSession, *, user_id: int, tenant_id: str
    ) -> Dict[str, Any]:
        """查询授权角色 - Plus-UI兼容接口"""
        # 获取用户当前角色
        user_roles_stmt = (
            select(Role)
            .join(sys_user_role, Role.role_id == sys_user_role.c.role_id)
            .where(
                sys_user_role.c.user_id == user_id,
                Role.tenant_id == tenant_id,
                Role.del_flag == "0",
            )
        )

        result = await db.execute(user_roles_stmt)
        user_roles = result.scalars().all()

        # 获取所有可用角色
        all_roles_stmt = select(Role).where(
            Role.tenant_id == tenant_id, Role.del_flag == "0", Role.status == "0"
        )

        result = await db.execute(all_roles_stmt)
        all_roles = result.scalars().all()

        return {
            "user": {"userId": user_id},
            "roles": [
                {
                    "roleId": role.role_id,
                    "roleName": role.role_name,
                    "roleKey": role.role_key,
                    "roleSort": role.role_sort,
                    "status": role.status,
                    "flag": True,
                }
                for role in all_roles
            ],
        }

    async def update_user_roles(
        self, db: AsyncSession, *, user_id: int, role_ids: List[int], tenant_id: str
    ) -> bool:
        """更新用户角色 - Plus-UI兼容接口"""
        return await self._assign_user_roles(db, user_id, role_ids)

    async def get_current_user_info(
        self, db: AsyncSession, *, user: User
    ) -> Dict[str, Any]:
        """获取当前用户信息 - Plus-UI兼容接口"""
        # 获取用户权限
        permissions = await self.get_user_permissions(db, user.user_id, user.tenant_id)

        # 获取用户角色
        roles = []
        for role in user.roles:
            if role.del_flag == "0":
                roles.append(role.role_key)

        return {
            "user": {
                "userId": user.user_id,
                "userName": user.user_name,
                "nickName": user.nick_name,
                "email": user.email,
                "phonenumber": user.phonenumber,
                "sex": user.sex,
                "avatar": user.avatar,
                "admin": False,
                "deptId": user.dept_id,
                "createTime": user.create_time.isoformat()
                if user.create_time
                else None,
            },
            "roles": roles,
            "permissions": permissions,
        }

    async def get_user_permissions(
        self, db: AsyncSession, user_id: int, tenant_id: str
    ) -> List[str]:
        """获取用户权限列表"""
        # 通过用户角色获取菜单权限
        permissions_stmt = (
            select(Menu.perms)
            .distinct()
            .join(sys_role_menu, Menu.menu_id == sys_role_menu.c.menu_id)
            .join(sys_user_role, sys_role_menu.c.role_id == sys_user_role.c.role_id)
            .where(
                sys_user_role.c.user_id == user_id,
                Menu.tenant_id == tenant_id,
                Menu.del_flag == "0",
                Menu.perms.isnot(None),
                Menu.perms != "",
            )
        )

        result = await db.execute(permissions_stmt)
        permissions = [perm for perm in result.scalars().all() if perm]
        return permissions

    async def get_user_menu_permissions(
        self, db: AsyncSession, user_id: int, tenant_id: str
    ) -> List[Dict[str, Any]]:
        """获取用户菜单权限"""
        menus_stmt = (
            select(Menu)
            .join(sys_role_menu, Menu.menu_id == sys_role_menu.c.menu_id)
            .join(sys_user_role, sys_role_menu.c.role_id == sys_user_role.c.role_id)
            .where(
                sys_user_role.c.user_id == user_id,
                Menu.tenant_id == tenant_id,
                Menu.del_flag == "0",
                Menu.status == "0",
            )
            .order_by(Menu.order_num)
        )

        result = await db.execute(menus_stmt)
        menus = result.scalars().all()

        menu_list = []
        for menu in menus:
            menu_dict = {
                "menuId": menu.menu_id,
                "menuName": menu.menu_name,
                "parentId": menu.parent_id,
                "orderNum": menu.order_num,
                "path": menu.path,
                "component": menu.component,
                "menuType": menu.menu_type,
                "visible": menu.visible,
                "status": menu.status,
                "perms": menu.perms,
                "icon": menu.icon,
            }
            menu_list.append(menu_dict)

        return menu_list

    async def _assign_user_roles(
        self, db: AsyncSession, user_id: int, role_ids: List[int]
    ) -> bool:
        """分配用户角色"""
        # 删除现有角色关联
        delete_stmt = delete(sys_user_role).where(sys_user_role.c.user_id == user_id)
        await db.execute(delete_stmt)

        # 添加新的角色关联
        if role_ids:
            role_data = [
                {"user_id": user_id, "role_id": role_id} for role_id in role_ids
            ]
            insert_stmt = sys_user_role.insert().values(role_data)
            await db.execute(insert_stmt)

        await db.commit()
        return True

    async def _assign_user_posts(
        self, db: AsyncSession, user_id: int, post_ids: List[int]
    ) -> bool:
        """分配用户岗位"""
        # 删除现有岗位关联
        delete_stmt = delete(sys_user_post).where(sys_user_post.c.user_id == user_id)
        await db.execute(delete_stmt)

        # 添加新的岗位关联
        if post_ids:
            post_data = [
                {"user_id": user_id, "post_id": post_id} for post_id in post_ids
            ]
            insert_stmt = sys_user_post.insert().values(post_data)
            await db.execute(insert_stmt)

        await db.commit()
        return True


# 创建服务实例
user_service = UserService()
